
#include "stdafx.h"
#include "windows.h"


#ifndef _WIN32_DCOM
#define _WIN32_DCOM			// CoInitializeEx
#endif
#include <objbase.h>		// com init

#include "CDelare.h"
#include "cidiasymb2str.h"
#include "CSymbolFinder.h"


#include "SmpTst.h"
#include "CmdLnPars.h"


#ifdef __cplusplus
extern "C" {
#endif

void DIADeclareTest(SmpTstFunCntx* pv);

#ifdef __cplusplus
}
#endif


_tstring g_strDeclare=_T("unsigned long long **const(*const pppXXX[0x3])[4] [5 ]  [  66 ] ");

void DIADeclareTest(SmpTstFunCntx* pv)
{
	CDeclare declare(g_strDeclare.c_str());

	SMPTST_ASSERT_RETURN(pv, declare.Parse(), (TEXT("declare parse fail!!!\r\n")));

	_tstring strType;
	SMPTST_ASSERT_RETURN(pv, declare.GetType(&strType), (TEXT("declare GetType fail!!!\r\n")));

	_tstring strDeclarator;
	declare.GetDeclarator(&strDeclarator);

	_tstring strFix;
	declare.GetDclFixStr(&strFix);

	SMPTST_RSLT_RETURN(pv, TRUE, (TEXT("DIADeclareTest:\r\n\tDeclare string:%s\r\n\ttype:%s\r\n\tDeclarator:%s\r\n\tDeclareFix:%s\r\n"),\
				g_strDeclare.c_str(), strType.c_str(), strDeclarator.c_str(), strFix.c_str()));

}

SMPTST_FUNCTION(DIADeclareTest, TEXT("DIA declare test"));

CMDLINE_INIT_EXT_NAME_VAL(TEXT("declare"), _tstring, g_strDeclare, TEXT("declare string"));



#pragma comment( lib, "diaguids" )


void PrintDiaDataType(CDIADataType* p, ISmpIO* pSmpIo, BOOL fRecursePtr)
{
	_tstring strTmp;

	pSmpIo->Printf(_T("data property\r\n"));
	pSmpIo->IncDeep();
	p->GetDataName(&strTmp);
	pSmpIo->Printf(_T("name:%s!\r\n"), strTmp.c_str());
	p->GetDataDescriptor(&strTmp);
	pSmpIo->Printf(_T("Descriptor:%s!\r\n"), strTmp.c_str());
	long lOffset;
	pSmpIo->Printf(_T("offset:%d!\r\n"), p->GetOffset(&lOffset)?lOffset:0);
	pSmpIo->Printf(_T("%s static!\r\n"), p->IsStatic()?_T("is"):_T("not"));
	pSmpIo->Printf(_T("%s bit!\r\n"), p->IsBit()?_T("is"):_T("not"));
	DWORD dwPos, dwLen;
	if( p->GetBitInfo(&dwPos, &dwLen))
	{
		pSmpIo->Printf(_T("bitset Pos:%d, bitset len:%d!\r\n"), dwPos, dwLen);
	}
	pSmpIo->DecDeep();

	pSmpIo->Printf(_T("type property\r\n"));
	pSmpIo->IncDeep();
	p->GetTypeName(&strTmp);
	pSmpIo->Printf(_T("name:%s!\r\n"), strTmp.c_str());
	pSmpIo->Printf(_T("len:%d!\r\n"), p->GetLen());
	pSmpIo->Printf(_T("basetype:%s!\r\n"), CIDIASymb2Str::mapBasicType[p->GetBaseType()].c_str());
	pSmpIo->Printf(_T("udt type:%s!\r\n"), CIDIASymb2Str::mapUdtKind[p->GetUdtKind()].c_str());
	pSmpIo->Printf(_T("%s enum!\r\n"), p->IsEnum()?_T("is"):_T("not"));
	pSmpIo->Printf(_T("%s const!\r\n"), p->IsConst()?_T("is"):_T("not"));
	pSmpIo->Printf(_T("%s pointer!\r\n"), p->IsPtr()?_T("is"):_T("not"));
	pSmpIo->Printf(_T("%s array!\r\n"), p->IsArray()?_T("is"):_T("not"));

	pSmpIo->Printf(_T("--------\r\n"));

	if( (fRecursePtr) || (!p->IsPtr()) )
	{
		CDIADataType* pDataType;
		while(p->NextChild(&pDataType, NULL))
		{
			PrintDiaDataType(pDataType, pSmpIo, fRecursePtr);
			delete pDataType;
		}
	}
	pSmpIo->DecDeep();

	pSmpIo->Printf(_T("\r\n"));

};

typedef _com_ptr_t<_com_IIID<IDiaDataSource, &__uuidof(IDiaDataSource)> > IDiaDataSourcePtr;
typedef _com_ptr_t<_com_IIID<IDiaSession, &__uuidof(IDiaSession)> > IDiaSessionPtr;
typedef _com_ptr_t<_com_IIID<IDiaEnumSymbols, &__uuidof(IDiaEnumSymbols)> > IDiaEnumSymbolsPtr;

_tstring g_strPdbFile;

void DIADataTypeTest(SmpTstFunCntx* pv)
{
	SMPTST_ASSERT_RETURN(pv,  SUCCEEDED( CoInitializeEx( NULL, COINIT_MULTITHREADED ))	\
						,(_T("CoInitializeEx faild!")) );

//
// init dia 
	CSymbolFinder symbFd;
	SMPTST_ASSERT_RETURN(pv,  SUCCEEDED( symbFd.Init( g_strPdbFile.c_str() ))	\
						,(_T("Can't load Data From %s!"), g_strPdbFile) );

//
// get delcare
	CDeclare declare(g_strDeclare.c_str());
	SMPTST_ASSERT_RETURN(pv, declare.Parse(), (TEXT("declare parse fail!!!\r\n")));
	_tstring strType;
	SMPTST_ASSERT_RETURN(pv, declare.GetType(&strType), (TEXT("declare GetType fail!!!\r\n")));


// find types
	vector<IDiaSymbolPtr> vSymbolS;
	if(declare.IsDiaBaseType())
	{
		BaseTypeInfo btinfo;
		declare.GetBasicTypeDiaInfo(&btinfo);

		IDiaSymbol* psymbolBasic;
		SMPTST_ASSERT_RETURN(pv, symbFd.FindBasicSymbol(btinfo.btBaseType, btinfo.dwLen, &psymbolBasic)	\
							, (TEXT("can't find basic type:%s!\r\n"), btinfo.pszName));
		vSymbolS.push_back(psymbolBasic);
	}
	else
	{
		SMPTST_ASSERT_RETURN(pv, symbFd.FindSymbolS(strType.c_str(), &vSymbolS, SymTagNull) \
							, (TEXT("can't find type:s!\r\n"), strType.c_str()));
	}

	vector<CDclFix> vDclFixS;
	declare.GetDclFixS(&vDclFixS);

	for(vector<IDiaSymbolPtr>::iterator it=vSymbolS.begin(); it!=vSymbolS.end(); it++)
	{
		CDIAComposeType diaCmpsType(*it);
		for(vector<CDclFix>::iterator it_fix=vDclFixS.begin(); it_fix!=vDclFixS.end(); it_fix++)
		{
			diaCmpsType.PushFix(&(*it_fix));
		}
		CDIADataType dataType(&diaCmpsType);

		PrintDiaDataType(&dataType, EXTRACT_CNTX_IO(pv), TRUE);
	}
		
// !!! can't call here for when function return _com_ptr_t will call relese!!!
// so where to call CoUninitialize???
//	CoUninitialize();

	SMPTST_RSLT_RETURN(pv, TRUE, (TEXT("DIADataTypeTest ok\r\n")) );

}

SMPTST_FUNCTION(DIADataTypeTest, TEXT("DIA data type test"));

CMDLINE_INIT_EXT_NAME_VAL(TEXT("pdb_file"), _tstring, g_strPdbFile, TEXT("pdb file"));


